package com.istock.state.demo.service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.istock.base.common.api.model.ApiBaseResponse;
import com.istock.base.state.execute.ExecuteContext;
import com.istock.base.state.execute.StateExecutor;
import com.istock.base.state.model.ExecuteResult;
import com.istock.state.demo.api.NewMockService;
import com.istock.state.demo.constants.ChildOrderStatusEnum;
import com.istock.state.demo.constants.OrderInfoStatusEnum;
import com.istock.state.demo.dao.OrderGoodsMapper;
import com.istock.state.demo.dao.OrderInfoMapper;
import com.istock.state.demo.dao.OrderPayMapper;
import com.istock.state.demo.model.OrderGoods;
import com.istock.state.demo.model.OrderInfo;
import com.istock.state.demo.model.OrderInfoExample;
import com.istock.state.demo.model.OrderPay;

@Repository("newOrderInfoService")
public class NewOrderInfoService {

	@Autowired
	private OrderInfoMapper orderInfoMapper;
	@Autowired
	private OrderPayMapper orderPayMapper;
	@Autowired
	private OrderGoodsMapper orderGoodsMapper;
	
	@Autowired
	private NewMockService mockService;
	@Autowired
	private StateExecutor executor;
	
	/**controller中发起一个订单
	 * @param name
	 * @param status
	 * @param amount
	 * @return
	 */
	public OrderInfo createOrderInfo(String name , Integer status , BigDecimal amount) {
		OrderInfo orderInfo = new OrderInfo();
		orderInfo.setAmount(amount);
		orderInfo.setStatus(status);
		orderInfo.setName(name);
		orderInfo.setUpdateTime(new Date());
		orderInfoMapper.insertSelective(orderInfo);
		
		/*NewOrderInfo result = new NewOrderInfo();
		BeanUtils.copyProperties(orderInfo, result);*/
		
		return orderInfo;
	}
	
	public OrderInfo findOrderInfo(Long id) {
		OrderInfo orderInfo = orderInfoMapper.selectByPrimaryKey(id);
		/*NewOrderInfo result = new NewOrderInfo();
		BeanUtils.copyProperties(orderInfo, result);*/
		
		return orderInfo;
	}
	
	/**
	 * 
	 * 订单发起准备发起支付
	 * 状态由NO-PAY变成PAYING
	 * 同时创建支付订单
	 * 
	 * @param orderInfo
	 */
	public void toPay(OrderInfo orderInfo) {
		OrderInfoExample example = new OrderInfoExample();
		OrderInfoExample.Criteria criteria = example.createCriteria();
		criteria.andStatusEqualTo(OrderInfoStatusEnum.NO_PAY.getValue());
		criteria.andIdEqualTo(orderInfo.getId());
		OrderInfo updateObject = new OrderInfo();
		updateObject.setStatus(OrderInfoStatusEnum.PAYING.getValue());
		updateObject.setUpdateTime(new Date());
		int row = orderInfoMapper.updateByExampleSelective(updateObject, example);
		if(row != 1) {
			throw new RuntimeException("更新失败,回滚事务");
		}
		
		OrderPay payOrder = new OrderPay();
		payOrder.setAmount(orderInfo.getAmount());
		payOrder.setOrderId(orderInfo.getId());
		payOrder.setStatus(ChildOrderStatusEnum.WAIT.getValue());
		payOrder.setUpdateTime(new Date());
		payOrder.setRequestNo(RandomStringUtils.randomAlphanumeric(10));
		orderPayMapper.insertSelective(payOrder);
	}
	
	/**发送支付请求
	 * 入参只能有一个,ExecuteContext
	 * 返回值只能是String
	 * 发送支付请求给mock服务
	 * 假设发送的是同步请求,会直接返回结果
	 * 
	 * @param context
	 * @return
	 */
	//不允许有事务,因为内部有远程调用
	//这边只负责远程操作,不负责本地事务,本地事务会根据handler的结果返回,再来操作
	public String paySender(ExecuteContext context) {
		OrderPay payOrder = (OrderPay)context.getOrder();
		//用本地的pay的id,查询当前的订单是否已经被处理过
		ApiBaseResponse<String> searchResult = mockService.searchPay(payOrder.getId());
		//查询的结果有以下几种
		//1.没有记录
		//2.有记录,还没处理,和处理中重叠
		//3.处理中
		//4.成功 or 失败,明确的结果
		//5.查询失败,失败的查询,可以是有返回值的,也可以是请求超时,在请求的封装中,如果超时,不会抛出异常,而是searchResult==null
		if(searchResult == null) {
			//查询不知道结果,本地不能有任何报错,程序应该再次发起轮询
			return "P";
		}else if(searchResult.getCode().equalsIgnoreCase("NO_RECORD")) {
			//没有记录,发起支付
			Map<String , Object> paramMap = new HashMap<String , Object>();
			paramMap.put("payId", payOrder.getId());
			paramMap.put("amount", payOrder.getAmount());
			ApiBaseResponse<String> payResult = mockService.payApply(paramMap);
			//同步请求
			if(payResult != null) {
				//这边代表有结果,不管是成功还是失败,也可以是处理中
				return payResult.getCode();
			}
			//这边表示payResult为空,是支付请求不知道结果
			//和查询请求不知道结果是一个操作
		}else {
			//查询结果是处理中,成功,失败,直接返回
			return searchResult.getCode();
		}
		return "P";
	}
	
	/**
	 * 支付完成以后的回调保存
	 * 更新orderPay的状态
	 * 更新orderInfo的状态,如果支付结果为成功,orderInfo状态为PAYED,如果支付结果为失败,orderInfo状态为PAY_FAIL
	 * @param order
	 * @param handlerResult
	 */
	public void payResult(OrderPay order , String handlerResult) {
		OrderPay orderPay = new OrderPay();
		orderPay.setId(order.getId());
		orderPay.setStatus(handlerResult.equalsIgnoreCase("S")?ChildOrderStatusEnum.SUCCESS.getValue():ChildOrderStatusEnum.FAIL.getValue());
		orderPay.setUpdateTime(new Date());
		orderPayMapper.updateByPrimaryKeySelective(orderPay);
		
		OrderInfo orderInfo = new OrderInfo();
		orderInfo.setId(order.getOrderId());
		orderInfo.setUpdateTime(new Date());
		if(handlerResult.equalsIgnoreCase("S")) {
			orderInfo.setStatus(OrderInfoStatusEnum.PAYED.getValue());
			orderInfoMapper.updateByPrimaryKeySelective(orderInfo);
		}else if(handlerResult.equalsIgnoreCase("F")) {
			orderInfo.setStatus(OrderInfoStatusEnum.PAY_FAIL.getValue());
			orderInfoMapper.updateByPrimaryKeySelective(orderInfo);
		}
	}
	
	/**收到确定的支付成功通知
	 * 
	 * 订单准备发起发货
	 * 订单状态由PAYED变成SENDING
	 * 创建发货订单
	 * 
	 * @param orderInfo
	 */
	public void toGoods(OrderInfo orderInfo) {
		OrderInfoExample example = new OrderInfoExample();
		OrderInfoExample.Criteria criteria = example.createCriteria();
		criteria.andStatusEqualTo(OrderInfoStatusEnum.PAYED.getValue());
		criteria.andIdEqualTo(orderInfo.getId());
		
		OrderInfo updateObject = new OrderInfo();
		updateObject.setStatus(OrderInfoStatusEnum.SENDING.getValue());
		updateObject.setUpdateTime(new Date());
		int row = orderInfoMapper.updateByExampleSelective(updateObject, example);
		if(row != 1) {
			throw new RuntimeException("更新失败,回滚事务");
		}
		
		OrderGoods goods = new OrderGoods();
		goods.setOrderId(orderInfo.getId());
//		goods.setRequestNo(requestNo);
		goods.setStatus(ChildOrderStatusEnum.WAIT.getValue());
		goods.setUpdateTime(new Date());
		orderGoodsMapper.insertSelective(goods);
	}
	
	/**
	 * 支付成功,通知发货
	 * @param context
	 * @return
	 */
	public String goodsSender(ExecuteContext context) {
		OrderGoods orderGoods = (OrderGoods)context.getOrder();
		//用本地的goods的id,查询当前的订单是否已经被处理过
		ApiBaseResponse<String> searchResult = mockService.searchGoods(orderGoods.getId());
		//发货查询只有以下几种返回,通讯异常,没有记录,成功,失败
		//发货查询一定不为空
		//查询的结果有以下几种
		//1.没有记录
		//2.有记录,还没处理,和处理中重叠
		//3.处理中
		//4.成功 or 失败,明确的结果
		//5.查询失败,失败的查询,可以是有返回值的,也可以是请求超时,在请求的封装中,如果超时,不会抛出异常,而是searchResult==null
		if(searchResult == null) {
			//如果返回null,可能的原因很多,客户端不做任何动作
			return "P";
		}else if(searchResult.getCode().equalsIgnoreCase("NO_RECORD")) {
			ApiBaseResponse<String> goodsResult = mockService.goodsApply(orderGoods.getId());
			if(goodsResult != null) {
				//这边代表有结果,不管是成功还是失败,也可以是处理中
				return goodsResult.getCode();
			}
		}else {
			return searchResult.getCode();
		}
		return "P";
	}
	
	/**发货请求有结果以后,对发货的更新
	 * demo大小的限制,发货没有失败
	 * @param order
	 * @param handlerResult
	 */
	public void goodsResult(OrderGoods order , String handlerResult) {
		OrderGoods goods = new OrderGoods();
		goods.setId(order.getId());
		goods.setUpdateTime(new Date());
		goods.setStatus(handlerResult.equalsIgnoreCase("S")?ChildOrderStatusEnum.SUCCESS.getValue():ChildOrderStatusEnum.FAIL.getValue());
		orderGoodsMapper.updateByPrimaryKeySelective(goods);
		
		OrderInfo orderInfo = new OrderInfo();
		orderInfo.setId(order.getOrderId());
		orderInfo.setUpdateTime(new Date());
		if(handlerResult.equalsIgnoreCase("S")) {
			orderInfo.setStatus(OrderInfoStatusEnum.SUCCESS.getValue());
			orderInfoMapper.updateByPrimaryKeySelective(orderInfo);
		}
	}
	
	public ExecuteResult executeState(OrderInfo orderInfo , Map<String , Object> extensionMap) {
		ExecuteContext context = new ExecuteContext();
		context.setOrder(orderInfo);
		if(extensionMap != null) {
			context.getExtention().putAll(extensionMap);
		}
		return executor.execute(context);
	}
}
